/*
    1.日志格式化子项类实现 抽象基类+各子项派生类
    2.日志格式化类实现 日志消息的格式化功能
*/
#include <iostream>
#include <string>
#include <ctime>
#include <memory>
#include <vector>
#include <cassert>
#include <sstream>
#include <utility>
#include "message.hpp"

#ifndef __M_FORMAT_H__
#define __M_FORMAT_H__

namespace mylog{
    // 抽象格式化子项的基类
    class FormatItem{
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual void format(std::ostream &out, const logmsg &msg) = 0;
        virtual ~FormatItem(){}   // 设置一个虚析构 防止ptr销毁派生对象是未定义行为
    };

    // 由基类派生出不同的格式化子项类
    class TimeFormatItem : public FormatItem{
    public:
        TimeFormatItem(const std::string &fmt = "%H:%M:%S")
        :_fmt(fmt)
        {}

        void format(std::ostream &out, const logmsg &msg) override {
            // 1.时间戳转化为本地时区的“分解时间”存放到t中
            struct tm t;
            localtime_r(&msg._ctime, &t);
            // 2.把“分解后的时间”按指定格式fmt 格式化为字符串存放到buffer中
            char buffer[32] = {0};  
            strftime(buffer, sizeof(buffer) - 1, _fmt.c_str(), &t);
            out << buffer;
        }

    private:
        std::string _fmt;
    };

    class LevelFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << loglevel::toString(msg._level);
        }
    };

    class FileFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << msg._filename;
        }
    };

    class LineFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << msg._line;
        }
    };

    class TidFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << msg._tid;
        }
    };

    class LoggerFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << msg._logger;
        }
    };

    class MsgFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << msg._message;
        }
    };

    class TabFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << "\t";
        }
    };

    class NlineFormatItem : public FormatItem{
    public:
        void format(std::ostream &out, const logmsg &msg) override {
            out << "\n";
        }
    };

    class OtherFormatItem : public FormatItem{
    public:
        OtherFormatItem(const std::string &str)
        :_str(str)
        {}

        void format(std::ostream &out, const logmsg &msg) override {
            out << _str;
        }

    private:
        std::string _str;
    };


    /*  格式化规则字符
        %d 日期
        %T 缩进
        %t 线程ID
        %p 日志级别
        %c 日志器名称
        %f 文件名
        %l 行号
        %m 日志消息
        %n 换行
    */

    // 日志消息格式化类
    class Formatter{
        inline static const std::string defaultpattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n";

    public:
        using ptr = std::shared_ptr<Formatter>;

        Formatter(const std::string &pattern = defaultpattern)
        : _pattern(pattern)
        {
            // 初始化时检查格式化规则字符串是否可以解析成功
            assert(parsepattern());
        }

        // 格式化日志消息 两种接口
        void format(std::ostream &out, const logmsg &msg){
            for(auto &item : _items){
                item->format(out, msg);
            }
        }
        std::string format(const logmsg &msg){
            std::stringstream ss;
            for(auto &item : _items){
                item->format(ss, msg);
            }
            return ss.str();
        }

    private:
        // 解析格式化规则字符串
        bool parsepattern(){
            // 1.将解析出的格式化字符key 以及对应的value值存放到数组中
            std::vector<std::pair<std::string, std::string>> array;
            std::string key, value;
            size_t pos = 0;
            while(pos<_pattern.size()){
                // 常规字符 添加到value中继续后移
                if (_pattern[pos] !='%'){
                    value.push_back(_pattern[pos++]);
                    continue;
                }
                // “%%” 也属于常规字符 添加到value中继续后移
                if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%'){
                    value += "%%";
                    pos += 2;
                    continue;
                }
                // 规则字符 比如 "%d" 先将前面的常规字符串添加到数组中
                if(!value.empty()){
                    array.push_back({key, value});
                    value.clear();
                }

                // 当前字符对应的是'%' 后移一位之后才是规则字符赋值给key
                pos++;
                if (pos >= _pattern.size()){
                    std::cout << "%之后没有匹配的规则字符" << std::endl;
                    return false;
                }
                key = _pattern[pos];

                // 再后移一位 如果规则字符之后是'{' 说明还有子格式字符串
                pos++;
                if (pos < _pattern.size() && _pattern[pos] == '{'){
                    pos++;
                    while(pos<_pattern.size()&&_pattern[pos]!='}'){
                        value.push_back(_pattern[pos++]);
                    }
                    if (pos >= _pattern.size()){
                        std::cout << "{之后没有匹配的}" << std::endl;
                        return false;
                    }
                    pos++;
                }

                // 规则字符之后是普通字符就将key value值添加到数组中 重新置空key value 开始下一轮查找
                array.push_back({key, value});
                key.clear();
                value.clear();
            }

            // 2.遍历数组，依次创建格式化子项对象
            for(auto &item : array){
                _items.push_back(createitem(item.first, item.second));
            }

            return true;
        }

        // 根据每个格式化规则字符，创建对应的格式化子项对象
        FormatItem::ptr createitem(const std::string &key, const std::string &value){
            if (key == "d"){
                return std::make_shared<TimeFormatItem>(value);
            }
            if (key == "t"){
                return std::make_shared<TidFormatItem>();
            }
            if (key == "p"){
                return std::make_shared<LevelFormatItem>();
            }
            if (key == "c"){
                return std::make_shared<LoggerFormatItem>();
            }
            if (key == "f"){
                return std::make_shared<FileFormatItem>();
            }
            if (key == "l"){
                return std::make_shared<LineFormatItem>();
            }
            if (key == "m"){
                return std::make_shared<MsgFormatItem>();
            }
            if (key == "T"){
                return std::make_shared<TabFormatItem>();
            }
            if (key == "n"){
                return std::make_shared<NlineFormatItem>();
            }
            if(key == ""){
                return std::make_shared<OtherFormatItem>(value);
            }
            std::cout << "没有对应的格式化字符: % " << key << std::endl;
            abort();
            return FormatItem::ptr();
        }

    private: 
        std::string _pattern;                           // 格式化规则字符串
        std::vector<FormatItem::ptr> _items;            // 存放“指向格式化子项对象的指针”的指针数组
    };

    //const std::string Formatter::defaultpattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l] %m%n";
}

#endif